﻿using NAudio.Wave;
using PlayListSet.Entity;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Interop;
using System.Windows.Threading;

namespace PlayListSet.Comm
{
    public enum LocalAudioPlayState
    {
        None, Play, Stop, Error

    }
    public class LocalAudioPlay
    {
        NAudio.Wave.WaveOut waveOut;
        NAudio.Wave.AudioFileReader audioFileReader;
        Collection<PlayInfo> playList;
        private PlaybackState currentPlaybackState= PlaybackState.Stopped;
        public string channelName;
    
        public PlayInfo CurrentPlayInfo { get; private set; }
        public PlaybackState CurrentPlaybackState
        {
            set { currentPlaybackState = value; Console.WriteLine("set:"+ value); }
            get { return currentPlaybackState; }
        }
        Thread thread;
        private Dispatcher dispatcher1;
        public LocalAudioPlay(string channelName, Dispatcher dispatcher)
        {
            this.channelName = channelName;
            dispatcher1 = dispatcher;

            waveOut = new NAudio.Wave.WaveOut();
            waveOut.PlaybackStopped += WaveOut_PlaybackStopped;
            
            AppControl.Instance.TimeCodePlayContorl.OnTimeCodePlaybackState += TimeCodePlayContorl_OnTimeCodePlaybackState;
            //AppControl.Instance.TimeCodePlayContorl.TimeCodeChanged += TimeCodePlayContorl_TimeCodeChanged;
            //playList = AppControl.Instance.PlayInfoMap[channelName];
            thread = new Thread(TimeCodeUpdate);
            thread.IsBackground = true;
            thread.Start();
        }

        private void WaveOut_PlaybackStopped(object sender, StoppedEventArgs e)
        {
            CurrentPlaybackState = PlaybackState.Stopped;
        }
        private void Play()
        {
            dispatcher1.Invoke(new Action(() => {
                waveOut.Play();
            }));
          
            CurrentPlaybackState = PlaybackState.Playing;
        }
        private void Pause()
        {
            dispatcher1.Invoke(new Action(() => {
                waveOut.Pause();
            }));
            CurrentPlaybackState = PlaybackState.Paused;
        }
        private void Stop()
        {
            dispatcher1.Invoke(new Action(() => {
                waveOut.Stop();
            }));
            CurrentPlaybackState = PlaybackState.Stopped;
        }
        private void TimeCodeUpdate()
        {
            while (true)
            {
                try
                {
                    Thread.Sleep(33);
                    TimeCodePlayContorl_TimeCodeChanged(AppControl.Instance.TimeCodePlayContorl.GetCurrentTime());
                }
                catch (Exception ex)
                {
                    Console.WriteLine(  ex.Message);

                }
                finally
                {

                }
            }
        }
        private bool timeCodeChanged = false;
        private void TimeCodePlayContorl_TimeCodeChanged(TimeSpan currentTime)
        {
            if (timeCodeChanged) return;
            timeCodeChanged = true;
            try
            {


            if (playList.Count == 0) return;
            var currentInfo = GetCurrentPlayInfo(currentTime);
            if (currentInfo == null)
            {
                if (CurrentPlayInfo != null)
                {
                    Stop();
                    Console.WriteLine("currentInfo == null");
                    CurrentPlayInfo = null;
                }

                return;
            }
            if (currentInfo != CurrentPlayInfo)
            {
                CurrentPlayInfo = currentInfo;
                UpdatePlayInfo(CurrentPlayInfo, currentTime, TimeSpan.FromSeconds(0));
            }
            else if (CurrentPlayInfo != null)
            {
                if (CurrentPlayInfo.LocalAudioPlayState == LocalAudioPlayState.Play)
                {

                    //监测偏差
                    UpdatePlaySeek(CurrentPlayInfo, currentTime, TimeSpan.FromSeconds(0), 0.2);
                    //播控同步
                }
                else if (CurrentPlayInfo.LocalAudioPlayState == LocalAudioPlayState.Stop)
                {

                }
            }
            }
            finally
            {
                timeCodeChanged = false;

            }
        }
        private bool updatePlayInfo = false;
        private bool updatePlaySeek = false;

        private void UpdatePlayInfo(PlayInfo playInfo, TimeSpan currentTime, TimeSpan add)
        {
            if (updatePlayInfo) return;
            updatePlayInfo = true;
            try
            {
                if (!System.IO.File.Exists(playInfo.SourceUrl))
                {
                    return;
                }
                audioFileReader = new NAudio.Wave.AudioFileReader(playInfo.SourceUrl);
                audioFileReader.Volume = playInfo.Volume / 100f;
                playInfo.LocalAudioSourceTime = audioFileReader.TotalTime.TotalSeconds;
                var itemCt = currentTime.TotalSeconds - playInfo.StartTimeCode;
                var st = itemCt % playInfo.LocalAudioSourceTime;
                audioFileReader.CurrentTime =TimeSpan.FromSeconds(st)+add;
                waveOut.Init(audioFileReader);
                if (AppControl.Instance.TimeCodePlayContorl.PlaybackState == PlaybackState.Playing)
                {
                    OnPlayIndex = 15;
                    Play();
                }
                   
                playInfo.LocalAudioPlayState = LocalAudioPlayState.Play;
            }
            catch (Exception)
            {
                playInfo.LocalAudioPlayState = LocalAudioPlayState.Error;
                throw;
            }
            finally
            {
                updatePlayInfo = false;
            }
        }
        private int OnPlayIndex = 0;
        private int SeekNum = 0;
        private void UpdatePlaySeek(PlayInfo playInfo, TimeSpan currentTime, TimeSpan add, double offset)
        {
            if (updatePlaySeek) return;
            updatePlaySeek = true;
            if (OnPlayIndex > 0)
            {
                OnPlayIndex--;
                updatePlaySeek = false;
                return;
            }
            try
            {
                var ct = currentTime.TotalSeconds;
                if (ct >= playInfo.StartTimeCode && ct <= playInfo.EndTimeCode)
                {

                    var itemCt = ct - playInfo.StartTimeCode;
                    var st = itemCt % playInfo.LocalAudioSourceTime;
                    var clt = audioFileReader.CurrentTime.TotalSeconds;
                    var c = st - clt;
                    if (Math.Abs(c) > offset)
                    {
                        SeekNum++;
                        if (SeekNum > 10)
                        {
                            SeekNum = 0;
                            audioFileReader.CurrentTime = TimeSpan.FromSeconds(st) + add;
                            OnPlayIndex = 30;
                            Console.WriteLine(c);
                        }

                    }
                    else
                    {
                        SeekNum = 0;
                    }
                    if (AppControl.Instance.TimeCodePlayContorl.PlaybackState == PlaybackState.Playing)
                    {
                        if(CurrentPlaybackState != PlaybackState.Playing)
                        {
                            Play();
                            OnPlayIndex = 30;
                        }
                    }
                }
                else
                {
                    //不在范围内，停止播放
                    CurrentPlayInfo.LocalAudioPlayState = LocalAudioPlayState.Stop;
                    if (CurrentPlaybackState == PlaybackState.Playing)
                    {
                        Pause();
                    }
                }

            }
            finally
            {
                updatePlaySeek = false;
            }
        }
      
        private void TimeCodePlayContorl_OnTimeCodePlaybackState(NAudio.Wave.PlaybackState playbackState)
        {
            if (playbackState == PlaybackState.Stopped)
            {
                if(CurrentPlayInfo==null)return;
                CurrentPlayInfo.LocalAudioPlayState = LocalAudioPlayState.Stop;
                Stop();
            }
            else if(playbackState== PlaybackState.Playing)
            {
                TimeCodePlayContorl_TimeCodeChanged(AppControl.Instance.TimeCodePlayContorl.CurrentTime);
            }

        }

        private PlayInfo GetCurrentPlayInfo(TimeSpan timeSpan)
        {
            var s = timeSpan.TotalSeconds;
            for (int i = 0; i < playList.Count; i++)
            {
                var info = playList[i];

                if (s >= info.StartTimeCode && s <= info.EndTimeCode)
                    return info;
            }
            return null;
        }

        ~LocalAudioPlay()
        {
            thread.Abort();
            if (waveOut != null)
            {
                waveOut.Dispose();
            }
            //windows.Close();
        }
    }
}
